#include "State.h"

// Helper functions
// support only integers in decimal form
inline bool isNumberChar(char c) {
	return (c >= '0' && c <= '9');
}
// non ASCII letter chars are error chars
inline bool isLetterChar(char c) {
	return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
}

TokenType StateStart::operation(char c, Automat * a) {
	if (isNumberChar(c)) {
		a->setCurrentState(StateInteger::makeState());
	} else if (isLetterChar(c)) {
		a->setCurrentState(StateIdentifier::makeState());
	} else {
		switch ((int) c) {
		// signs
		case '+':
			return SIGN_PLUS;
		case '-':
			return SIGN_MINUS;
		case '/':
			return SIGN_DIV;
		case '*':
			return SIGN_MULTI;
		case '>':
			return SIGN_GREATER;
		case '=':
			return SIGN_ASSIGN;
		case '!':
			return SIGN_NOT;
		case '&':
			return SIGN_AND;
		case ';':
			return SIGN_SEMICOLON;
		case ')':
			return SIGN_CLOSEPAREN;
		case '{':
			return SIGN_OPENBRACE;
		case '}':
			return SIGN_CLOSEBRACE;
		case '[':
			return SIGN_OPENBRACKET;
		case ']':
			return SIGN_CLOSEBRACKET;

		case '<': // < or <=> sign
			a->setCurrentState(StateSmaller::makeState());
			break;

		case '(': // ( sign or comment (*
			a->setCurrentState(StateOpenParen::makeState());
			break;

		case '\0':
			return END_OF_FILE;

		// whitespace
		case ' ':
		case '\n':
		case '\r':
		case '\t':
			return SKIP;

		default:
			a->error();
			return ERROR;
		}
	}
	return NONE;
}

TokenType StateInteger::operation(char c, Automat * a) {
	if (isNumberChar(c)) {
		return NONE;
	} else {
		a->ungetChar();
		a->setCurrentState(StateStart::makeState());
		return INTEGER;
	}
}

TokenType StateIdentifier::operation(char c, Automat * a) {
	if (isNumberChar(c) || isLetterChar(c)) {
		return NONE;
	} else {
		a->ungetChar();
		a->setCurrentState(StateStart::makeState());
		return IDENTIFIER;
	}
}

TokenType StateOpenParen::operation(char c, Automat * a) {
	if (c == '*') {
		a->setCurrentState(StateCommentBegin::makeState());
	} else {
		a->ungetChar();
		a->setCurrentState(StateStart::makeState());
		return SIGN_OPENPAREN;
	}
	return NONE;
}

TokenType StateCommentBegin::operation(char c, Automat * a) {
	if (c == '*') {
		a->setCurrentState(StateCommentEnd::makeState());
	} else {
		a->setCurrentState(StateCommentBegin::makeState());
	}
	return NONE;
}

TokenType StateCommentEnd::operation(char c, Automat * a) {
	if (c == ')') {
		a->setCurrentState(StateStart::makeState());
		return COMMENT;
	} else {
		a->setCurrentState(StateCommentBegin::makeState());
		return NONE;
	}
}

TokenType StateSmaller::operation(char c, Automat * a) {
	if (c == '=') {
		a->setCurrentState(StatePossibleEqual::makeState());
		return NONE;
	} else {
		a->ungetChar();
		a->setCurrentState(StateStart::makeState());
		return SIGN_SMALLER;
	}
}

TokenType StatePossibleEqual::operation(char c, Automat * a) {
	if (c == '>') {
		a->setCurrentState(StateStart::makeState());
		return SIGN_EQUAL;
	} else {
		a->ungetChar(2);
		a->setCurrentState(StateStart::makeState());
		return SIGN_OPENPAREN;
	}
}
